/**
 * calculator
 *
 * @author : tzy
 * @Date : 2021-03-16
 * @Description:
 **/

package com.tang.calculator;

import com.tang.calculator.context.CalculateContext;
import com.tang.calculator.symbols.*;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class FormulaSpliter {

    @Autowired
    List<OperatorSymbol> operatorSymbols;

    @Autowired
    ValueSymbolFactory valueSymbolFactory;

    public void split(CalculateContext context) {
        String formula = context.getFormula();
        List<Symbol> symbolList = context.getSymbolList();
        this.split(formula, symbolList);

        //处理负号，如果减号的前面放的是一个符号，那么需要补上一个0
        this.resolveNegative(context);

        //处理函数，如果函数是没有参数的，则默认加上一个null值作为它的参数
        this.resolveFunctionArgs(context);
    }

    private void resolveFunctionArgs(CalculateContext context) {
        List<Symbol> symbolList = context.getSymbolList();
        for (int i = symbolList.size() - 1; i > 0; i--) {
            Symbol currentSymbol = symbolList.get(i);
            Symbol lastSymbol = symbolList.get(i - 1);

            if (currentSymbol instanceof RightBracket && lastSymbol instanceof LeftBracket) {
                symbolList.add(i, valueSymbolFactory.createNull());
            }
        }
    }

    private void resolveNegative(CalculateContext context) {
        List<Symbol> symbolList = context.getSymbolList();
        for (int i = symbolList.size() - 1; i >= 0; i--) {
            Symbol symbol = symbolList.get(i);
            if (symbol instanceof SubstractSymbol) {
                if (
                        (i > 0 && symbolList.get(i - 1) instanceof OperatorSymbol)
                                || i == 0
                ) {
                    symbolList.add(i, valueSymbolFactory.create("0"));
                }
            }
        }
    }

    private void split(String formula, List<Symbol> symbolList) {
        int start = 0, end = 1, length = formula.length();

        while (start < length && end <= length) {
            Position position = getOperator(formula, start, end, symbolList);
            start = position.getEnd();

            while (start < length && formula.substring(start, start + 1).equals(" ")) start++;

            end = start + 1;
        }
    }

    private Position getOperator(String formula, int start, int end, List<Symbol> symbolList) {

        OperatorSymbol currentOperation = null;
        for (OperatorSymbol operatorSymbol : operatorSymbols) {
            String name = operatorSymbol.getName();
            int nameLength = name.length();
            int endTemp = start + nameLength;

            if (endTemp <= formula.length() && formula.substring(start, endTemp).equals(name)) {
                if (currentOperation == null) {
                    currentOperation = operatorSymbol;
                } else if (operatorSymbol.getName().length() > currentOperation.getName().length()) {
                    currentOperation = operatorSymbol;
                }
            }
        }
        if (currentOperation != null) {
            //这是一个运算符
            symbolList.add(currentOperation);
            end = start + currentOperation.getName().length();
            return new Position(start, end);
        }

        if (formula.charAt(start) == '\'') {
            //这是一个字符串
            StringBuilder sb = new StringBuilder();
            end = start + 1;
            while (end < formula.length() && formula.charAt(end) != '\'')
                sb.append(formula.charAt(end++));
            if (end >= formula.length())
                throw new RuntimeException("字符串少写一个单引号，请检查公式: " + formula);
            ValueSymbol valueSymbol = valueSymbolFactory.createString(sb.toString());
            symbolList.add(valueSymbol);
            start = end + 1;
            end = start;
            return new Position(start, end);
        }

        //这是一个操作数
        boolean flag = false;
        while (end <= formula.length()) {
            String substring = formula.substring(end - 1, end);
            for (OperatorSymbol operatorSymbol : operatorSymbols) {
                String name = operatorSymbol.getName();
                if (operatorSymbol.getName().startsWith(substring) || substring.equals(" ")) {
                    if (substring.equals(" ")) {
                        flag = true;
                        break;
                    } else {
                        int startTemp = end - 1, endTemp = name.length() + startTemp;
                        if (endTemp <= formula.length() && formula.substring(startTemp, endTemp).equals(operatorSymbol.getName())) {
                            flag = true;
                            break;
                        }
                    }
                }
            }
            if (flag) {
                break;
            }
            end++;
        }
        end--;
        String substring = formula.substring(start, end);
        ValueSymbol valueSymbol = valueSymbolFactory.create(substring);
        symbolList.add(valueSymbol);
        return new Position(start, end);
    }

    @Data
    class Position {
        int start;
        int end;

        public Position() {
        }

        public Position(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }

}
